let _MoveboxShadow = null;

export const config = {
    iconWidth: 50,
    iconHeight: 50,
    iconMargin: 10,
};

// this.tempData = {
//     dom: curDom,
//     map: map,
//     iconCount: [w, h], // 当前的大小
//     posi: [x, y], // 当前位移前的位置
//     curPosiIndex: [x, y], // 当前的位置的下标
// }

export class MoveboxShadow {
    static getInstance() {
        if (!_MoveboxShadow) {
            _MoveboxShadow = new MoveboxShadow();
        }
        return _MoveboxShadow;
    }

    constructor() {
        this.dom = this.getDom();
        this.moveDoms = [];
        // this._createBoxTest();
    }

    //shadow需要的初始量
    getAttr() {
        return {
            posiIndex: [0, 0], //起始下标
            whCount: [1, 1], //宽高长度
            posiResetTime: Math.random() * 200 + 300, //位置重定向时间的延迟
            margin: [0, 0, 0, 0], //是否停靠右面/下方,只会在加载时进行判定,使用时posiIndex会失效
        };
    }

    //会在每个icon加载完毕时调用,且在onMounted优先级最高
    init(comp) {
        const root = comp.getRoot();
        const attr = comp.getAttr();

        //判断是否贴边,对贴边进行初始化
        this._setMargin(attr);
        //进行大小初始化
        this._setTransform(attr);

        this.moveDoms.push({
            id: root.getUid(),
            attr: attr,
            comp: comp,
        });

        const xy = MoveboxShadow.computePosi(attr.posiIndex);
        const wh = MoveboxShadow.computeWH(attr.whCount);
        return [xy[0], xy[1], wh[0], wh[1]];
    }

    //组件卸载时调用
    rem(_id) {
        this.moveDoms = this.moveDoms.filter((u) => u.id != _id);
    }

    //初始化位置下标(防止被遮挡)
    initPosiIndex(_id) {
        this.getBoxPosiIndex(_id, false);
        //检测可以放下的位置
        const { map, iconCount, posi } = this.tempData;
        //先判断当前位置是否被占了
        if (this._isPosiOK(posi, iconCount)) {
            return posi;
        }

        let exist = false;
        let curPosi = [0, 0];
        for (let x = 0; x < map[0].length; x++) {
            for (let y = 0; y < map.length; y++) {
                if (map[y][x] == 0) {
                    //开始检测长度
                    if (iconCount[0] + x > map[0].length) {
                        continue;
                    }
                    if (iconCount[1] + y > map.length) {
                        continue;
                    }
                    //依次检测
                    let isExist = true;
                    for (let cury = 1; cury < iconCount[1]; cury++) {
                        for (let curx = 1; curx < iconCount[0]; curx++) {
                            if (map[y + cury][x + curx] == 1) {
                                isExist = false;
                                break;
                            }
                        }
                        if (!isExist) break;
                    }
                    if (!isExist) {
                        continue;
                    }
                    //通过
                    exist = true;
                    curPosi = [x, y];
                    break;
                }
            }
            if (exist) break;
        }
        return curPosi;
    }

    //#region 位移核心逻辑
    //生成临时移动数据
    getBoxPosiIndex(_id, isMove = true) {
        const elem = this.moveDoms;
        const map = this._creatrPosiBox();
        for (let i = 0; i < elem.length; i++) {
            const { id, attr } = elem[i];
            if (id == _id) {//如果是本元素就不再写入位置
                continue;
            }

            const curCount = attr.whCount;
            const curPosi = attr.posiIndex;

            //插入map
            for (let y = 0; y < curCount[1]; y++) {
                for (let x = 0; x < curCount[0]; x++) {
                    map[y + curPosi[1]][x + curPosi[0]] = 1;
                }
            }
        }

        //本次移动的数据进行解构
        const comp = this.getCurComp(_id);
        const attr = comp.getAttr();
        const count = attr.whCount;
        const posi = attr.posiIndex;
        this.tempData = {
            id: _id,
            map: map,
            iconCount: count,
            posi: posi,
        };

        const curPosi = MoveboxShadow.computePosi(posi);
        if (isMove) this.getShadowPosi(curPosi[0], curPosi[1]);

        return map;
    }

    //移动判定
    getShadowPosi(x, y) {
        const { iconMargin, iconHeight, iconWidth } = config;
        const { map, iconCount } = this.tempData;

        const dom = this.getDom();
        //计算坐标
        let curX = Math.round((x - 10) / 60);
        let curY = Math.round((y - 10) / 60);

        //限制在屏幕内
        curX = Math.max(Math.min(map[0].length - iconCount[0], curX), 0);
        curY = Math.max(Math.min(map.length - iconCount[1], curY), 0);

        //判断是否已经有了
        let exist = false;
        for (let y = 0; y < iconCount[1]; y++) {
            for (let x = 0; x < iconCount[0]; x++)
                if (map[y + curY][x + curX] == 1) {
                    exist = true;
                    break;
                }
            if (exist) break;
        }
        if (exist) return;

        const w = (iconMargin + iconWidth) * iconCount[0] - iconMargin;
        const h = (iconMargin + iconHeight) * iconCount[1] - iconMargin;
        //移动shadowDom
        this.tempData.curPosiIndex = [curX, curY];
        dom.setAttribute(
            "style",
            `width:${w}px;height:${h}px;top:${curY * 60 + 10}px;left:${curX * 60 + 10
            }px;opacity:1;`
        );
        return [curX, curY];
    }

    //移动锁定
    clear() {
        const { curPosiIndex, id, posi } = this.tempData;
        const comp = this.getCurComp(id);
        const attr = comp.getAttr();

        attr.posiIndex = curPosiIndex ? curPosiIndex : posi;
        const [curX, curY] = attr.posiIndex;

        this.getDom().setAttribute(
            "style",
            `top:${curY * 60 + 10}px;left:${curX * 60 + 10}px;opacity:0;`
        );
        return [curX, curY];
    }
    //#endregion

    //#region getData
    //获取指定的Comp由rootDom
    getCurComp(_id) {
        return this.moveDoms.find((u) => u.id == _id).comp;
    }

    getCurData(_id) {
        return this.moveDoms.find((u) => u.id == _id);
    }

    //获取shadowDom
    getDom() {
        if (!this.dom) {
            const div = document.createElement("div");
            div.setAttribute("class", "moveBox-shadow");
            document.body.append(div);
            this.dom = div;
        }
        return this.dom;
    }
    //#endregion

    //初始化大小
    _setTransform(attr) {
        let [w, h] = attr.whCount;
        const map = this._getMap();
        if (w == -1)
            w = map[0].length;
        if (h == -1)
            h = map.length;

        w = Math.min(Math.max(w, 0), map[0].length);
        h = Math.min(Math.max(h, 0), map.length);
        attr.whCount = [w, h];
        return attr.whCount;
    }

    //判断是否贴边
    _setMargin(attr) {
        const [t, r, b, l] = attr.margin;
        const [w, h] = attr.whCount;

        const map = this._getMap();
        const [wMax, hMax] = [map[0].length, map.length];
        let [x, y] = attr.posiIndex;
        if (t == 1 && b == 1) {//高度居中
            y = parseInt((hMax - h) / 2);
        } else if (b == 1) {
            y = hMax - y - h;
        }

        if (l == 1 && r == 1) {
            x = parseInt((wMax - w) / 2);
        } else if (r == 1) {
            x = wMax - x - w;
        }

        x = Math.max(Math.min(wMax - w, x), 0);
        y = Math.max(Math.min(hMax - h, y), 0);

        attr.posiIndex = [x, y];
    }

    //可以使用会返回true
    _isPosiOK([curX, curY], iconCount) {
        const { map } = this.tempData;
        let exist = true;
        for (let y = 0; y < iconCount[1]; y++) {
            for (let x = 0; x < iconCount[0]; x++)
                if (map[y + curY][x + curX] == 1) {
                    exist = false;
                    break;
                }
            if (!exist) break;
        }
        return exist;
    }

    _creatrPosiBox() {
        const { iconMargin, iconHeight, iconWidth } = config;
        const [viewW, viewH] = [
            document.documentElement.clientWidth,
            document.documentElement.clientHeight,
        ];
        const maxW = parseInt((viewW - iconMargin) / (iconMargin + iconWidth));
        const maxH = parseInt((viewH - iconMargin) / (iconMargin + iconHeight));
        const cur = [];
        for (let h = 0; h < maxH; h++) {
            var wArr = new Array(maxW);
            wArr.fill(0);
            cur.push(wArr);
        }
        this._tempMap = cur;
        return cur;
    }

    //创建map并且去除自己
    _createPosiBoxOfCur(_id) {
        const elem = this.moveDoms;
        const map = this._creatrPosiBox();
        for (let i = 0; i < elem.length; i++) {
            const { id, attr } = elem[i];
            if (id == _id) {//如果是本元素就不再写入位置
                continue;
            }

            const curCount = attr.whCount;
            const curPosi = attr.posiIndex;

            //插入map
            for (let y = 0; y < curCount[1]; y++) {
                for (let x = 0; x < curCount[0]; x++) {
                    map[y + curPosi[1]][x + curPosi[0]] = 1;
                }
            }
        }
        return map;
    }

    _createBoxTest() {
        const { iconMargin, iconHeight, iconWidth } = config;
        const cur = this._creatrPosiBox();
        for (let h = 0; h < cur.length; h++) {
            for (let w = 0; w < cur[h].length; w++) {
                const div = document.createElement("div");
                div.setAttribute("class", "moveBox-shadow");
                div.setAttribute(
                    "style",
                    `background-color: rgb(245, 108, 108);outline: 0px solid rgb(245, 108, 108);box-shadow: 0 0 0px 0px rgb(245, 108, 108);top:${h * (iconHeight + iconMargin) + iconMargin
                    }px;left:${w * (iconWidth + iconMargin) + iconMargin}px;opacity:1;`
                );
                document.body.append(div);
            }
        }
    }

    _getMap() {
        if (this._tempMap)
            return this._tempMap;
        else
            return this._creatrPosiBox();
    }

    static computePosi([x, y]) {
        const { iconMargin, iconHeight, iconWidth } = config;
        return [
            x * (iconWidth + iconMargin) + iconMargin,
            y * (iconHeight + iconMargin) + iconMargin,
        ];
    }

    static computeWH([w, h]) {
        const { iconMargin, iconHeight, iconWidth } = config;
        return [
            w * iconWidth + (w - 1) * iconMargin,
            h * iconHeight + (h - 1) * iconMargin,
        ];
    }
}
